package org.tacticalTroopers.jme.server;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.PropertyConfigurator;
import org.tacticalTroopers.jme.common.message.GameState;
import org.tacticalTroopers.jme.common.message.Information;
import org.tacticalTroopers.jme.server.object.ServerGameArea;
import org.tacticalTroopers.jme.server.object.ServerGameMap;
import org.tacticalTroopers.jme.server.object.ServerPlayer;

import com.jme3.network.connection.Client;




public class TacticalTroopersServer {
	Log log = LogFactory.getLog(getClass());

	GameManager gameManager;
	ServerGameArea gameArea;
	Boolean running = false;
	List<NetworkClientHandler> clientHanlders = new ArrayList<NetworkClientHandler>();
	List<NetworkClientHandler> clientHandlerToRemove = new ArrayList<NetworkClientHandler>();;
	List<Client> clients = new ArrayList<Client>();
	Scheduler scheduler;
	Integer frameDuration = 1000/40;
	
	LinkedList<Information> informationQueue = new LinkedList<Information>();

	

	PlayerNameManager playerNameManager;
	

	public TacticalTroopersServer() {
		PropertyConfigurator.configure("log4j.properties");
		log.info("[SERVER]");
		scheduler = new Scheduler();
		gameManager = new GameManager(this);
		playerNameManager = new PlayerNameManager();
		gameArea = new ServerGameArea();
		gameArea.setMap(new ServerGameMap());
		gameManager.setGameArea(gameArea);
		gameManager.createBox();
		
		//scheduler.setNoFramePerSecond(40);
		scheduler.setFrameDuration(frameDuration);

		NetworkManager nm = new NetworkManager();

		try {
			nm.init(56650,this);
		} catch (IOException e) {
			e.printStackTrace();
		}


		running = false;
		
	}
	
	public void setPlayerNames(Integer id,String name){
		playerNameManager.setPlayerName(id, name);
	}

	public void addClientHandler(NetworkClientHandler ch) {
		ServerPlayer player = gameManager.createPlayer();
		ch.initPlayer(player);
		ch.initGameArea(gameArea);
		
		synchronized (this.clientHanlders) {
			clientHanlders.add(ch);
		}
		
	}
	

	public void start() {
		running = true;
		new Thread(new Runnable(){

			@Override
			public void run() {
				while(running){
					step();
				}
			}
		}).start();
	}


	public void step(){
		scheduler.waitToNextTop();
		gameManager.step(frameDuration);
		synchronized (this.clientHanlders) {
			
			for(NetworkClientHandler ch : clientHanlders){
				GameState gs = gameArea.getGameState().getGameStateMessage();
				/*if(playerNameManager.isNamesNeedToBroadcasted()){
					gs.setPlayerNames(playerNameManager.getPlayerNamesMessage());
				}*/
				log.debug("Sending:"+gs);
				try {
					ch.sendNotCatched(gs);
					for(Information info : informationQueue){
						log.info("Sending:"+info);
						ch.sendNotCatched(info);
					}
					
					if(playerNameManager.isNamesNeedToBroadcasted()){
						ch.sendNotCatched(playerNameManager.getPlayerNamesMessage());
					}
					
					if(gameManager.getTeamManager().isTeamsNeedToBroadcasted()){
						ch.sendNotCatched(gameManager.getTeamManager().getTeamsMessage());
					}
					
				} catch (IOException e) {
					log.error(e);
					clientHandlerToRemove.add(ch);
				}
				
				
				
				
			}
			if(clientHandlerToRemove.size()>0){
				for(NetworkClientHandler nch  : clientHandlerToRemove){
					removeClientHandler(nch);
				}
				clientHandlerToRemove.clear();
			}
			informationQueue.clear();
		}
		playerNameManager.setNamesNeedToBroadcasted(false);
		gameManager.getTeamManager().setTeamsNeedToBroadcasted(false);
		
		/*synchronized (this.clientHanlders) {
			for(NetworkClientHandler ch : clientHanlders){
				if(playerNameManager.isNamesNeedToBroadcasted()){
					try {
						ch.sendNotCatched(playerNameManager.getPlayerNamesMessage());
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}*/
		
	}

	public static void main(String[] args) {
		new TacticalTroopersServer().start();
	}

	public void removeClientHandler(NetworkClientHandler clientHandler) {
		gameManager.removePlayer(clientHandler.getPlayer());
		synchronized (this.clientHanlders) {
			clientHanlders.remove(clientHandler);
		}
	}
	
	public void addToInformationQueue(Information info) {
		informationQueue.addLast(info);
	}

	public PlayerNameManager getPlayerManager() {
		return playerNameManager;
	}

	
}
